package com.atguigu.tingshu.album.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.common.anno.GuiguCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumAttributeValueService;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;
	@Autowired
	private AlbumAttributeValueService albumAttributeValueService;
	@Autowired
	private AlbumStatMapper albumStatMapper;
    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;
	@Autowired
	private RedisTemplate<String,String> redisTemplate;
	@Autowired
	private RedissonClient redissonClient;

	@Transactional
	@Override
	public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {
		//1.保存专辑的基本信息到albumInfo表中
		AlbumInfo albumInfo= new AlbumInfo();	//创建AlbumInfo对象，封装要保存到专辑的数据
		BeanUtils.copyProperties(albumInfoVo,albumInfo);	//进行对象属性的copy，要求两个对象属性名称和属性类型必须一致
		albumInfo.setUserId(AuthContextHolder.getUserId());		//获取当前登录用户的id
		//如果专辑是vip免费或者付费，需要给专辑设置一个免费的试听声音集数
		String payType = albumInfoVo.getPayType();
		if(!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(payType)){
			albumInfo.setTracksForFree(5);
		}
		//审核通过
		albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
		albumInfoMapper.insert(albumInfo);		//保存专辑数据
		//2.保存专辑属性值数据到album_attribute_value中
		List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
		List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueVoList.stream().map(albumAttributeValueVo -> {
			AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
			albumAttributeValue.setAlbumId(albumInfo.getId());
			albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
			albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
			return albumAttributeValue;
		}).collect(Collectors.toList());
		albumAttributeValueService.saveBatch(albumAttributeValueList);
		//3.初始化专辑的统计数据到album_stat表
		this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_PLAY);
		this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_SUBSCRIBE);
		this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_BROWSE);
		this.saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_COMMENT);
	}

	@Override
	public IPage<AlbumListVo> findUserAlbumPage(Integer pageNo, Integer pageSize,AlbumInfoQuery albumInfoQuery) {
		IPage<AlbumListVo> page = new Page<>(pageNo,pageSize);	//封装分页查询参数
		Long userId = AuthContextHolder.getUserId();
		albumInfoQuery.setUserId(userId);
		IPage<AlbumListVo> pageList = albumInfoMapper.findUserAlbumPage(page,albumInfoQuery);
		return pageList;
	}

	@Transactional
	@Override
	public void removeAlbumInfo(Integer id) {
		//从album_info表中根据专辑id删除专辑数据
		albumInfoMapper.deleteById(id);
		//从album_attribute_value表中根据专辑id删除专辑属性值数据
		LambdaQueryWrapper<AlbumAttributeValue> albumAttributeValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
		albumAttributeValueLambdaQueryWrapper.eq(AlbumAttributeValue::getAlbumId,id);
		albumAttributeValueService.remove(albumAttributeValueLambdaQueryWrapper);
		//从album_stat表中根据专辑id删除专辑统计数据
		LambdaQueryWrapper<AlbumStat> albumStatLambdaQueryWrapper = new LambdaQueryWrapper<>();
		albumStatLambdaQueryWrapper.eq(AlbumStat::getAlbumId,id);
		albumStatMapper.delete(albumStatLambdaQueryWrapper);
	}

	//todo ???
	@GuiguCache(cacheKey = RedisConstant.ALBUM_INFO_PREFIX+"#{#params[0]}")
	@Override
	public AlbumInfo getAlbumInfo(Long albumId) {        //根据专辑id查询专辑基本信息album_info和专辑的属性值数据album_attribute_value
		return albumInfoMapper.getAlbumInfo(albumId);    //查询缓存优化前
	}
	/**todo-1
	 * 为了提高该接口的数据查询效率，添加查询缓存
	 * 查询缓存思想：
	 * 1、先从缓存中查询数据，缓存中如果存在数直接进行返回
	 * 2、缓存中不存在数据，再查询数据库，然后把数据库中查询到的数据返回。但是在返回之前需要将数据存储到缓存中。
	 */
	public AlbumInfo getAlbumInfoRedisson(Long albumId) {
		//从缓存中查询数据
		String albumInfoKey = RedisConstant.ALBUM_INFO_PREFIX + albumId;
		String albumInfoJSON = redisTemplate.opsForValue().get(albumInfoKey);
		if (!StringUtils.isEmpty(albumInfoJSON)){
			AlbumInfo albumInfo = JSON.parseObject(albumInfoJSON, AlbumInfo.class);
			log.info("从缓存查询到了专辑数据……");
			return albumInfo;
		}
		//todo-2
		//使用分布式锁解决缓存击穿问题
		RLock lock = redissonClient.getLock(RedisConstant.ALBUM_LOCK_SUFFIX + albumId);
		boolean tryLock = lock.tryLock();
		if (tryLock){			//获取到锁，从数据库查询数据
			log.info(Thread.currentThread().getId()+"该线程获取到了分布式锁，查询数据……");
			try{
				//从数据库查询数据
				AlbumInfo albumInfo = albumInfoMapper.getAlbumInfo(albumId);
				//将查询到的数据保存到redis
				redisTemplate.opsForValue().set(albumInfoKey,JSON.toJSONString(albumInfo),RedisConstant.ALBUM_TIMEOUT,TimeUnit.DAYS);
				log.info("从数据库查询到了……数据");
				//返回数据
				return albumInfo;
			} catch (Exception e) {
				e.printStackTrace();
                throw new GuiguException(ResultCodeEnum.DATA_ERROR);
            }finally {
				log.info(Thread.currentThread().getId()+"该线程释放了分布式锁，查询数据……");
				lock.unlock();
			}
        }else {
			albumInfoJSON = redisTemplate.opsForValue().get(albumInfoKey);
			if (!StringUtils.isEmpty(albumInfoJSON)){
				AlbumInfo albumInfo = JSON.parseObject(albumInfoJSON, AlbumInfo.class);
				log.info(Thread.currentThread().getId()+"从缓存查询到了专辑数据……");
				return albumInfo;
			}else {
				log.info(Thread.currentThread().getId()+"该线程暂时没有从redis中查询到数据");
				return this.getAlbumInfo(albumId);
			}
		}

	}


	@Transactional
	@Override
	public void updateAlbumInfo(Integer albumId, AlbumInfoVo albumInfoVo) {
		//修改专辑的基本数据
		AlbumInfo albumInfo = this.getById(albumId);
		BeanUtils.copyProperties(albumInfoVo,albumInfo);
		this.updateById(albumInfo);
		//修改专辑的属性值数据
		//根据专辑的id先删除之前的属性值数据
		LambdaQueryWrapper<AlbumAttributeValue> albumAttributeValueLambdaQueryWrapper = new LambdaQueryWrapper<>();
		albumAttributeValueLambdaQueryWrapper.eq(AlbumAttributeValue::getAlbumId,albumId);
		albumAttributeValueService.remove(albumAttributeValueLambdaQueryWrapper);
		//新增新的属性值数据
		List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
		List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueVoList.stream().map(albumAttributeValueVo -> {
			AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
			albumAttributeValue.setAlbumId(Long.valueOf(albumId));
			albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
			albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
			return albumAttributeValue;
		}).collect(Collectors.toList());
		albumAttributeValueService.saveBatch(albumAttributeValueList);
	}


	@Override
	public List<AlbumInfo> findUserAllAlbumList() {
		//根据当前用户id查询专辑列表数据
		Long userId = AuthContextHolder.getUserId();
		LambdaQueryWrapper<AlbumInfo> albumInfoLambdaQueryWrapper=new LambdaQueryWrapper<>();
		albumInfoLambdaQueryWrapper.eq(AlbumInfo::getUserId,userId);
		albumInfoLambdaQueryWrapper.select(AlbumInfo::getId,AlbumInfo::getAlbumTitle).orderByDesc(AlbumInfo::getId);

		List<AlbumInfo> albumInfoList = albumInfoMapper.selectList(albumInfoLambdaQueryWrapper);
		return albumInfoList;
	}

	public void saveAlbumStat(Long albumId, String statType) {
		AlbumStat albumStat = new AlbumStat();
		albumStat.setAlbumId(albumId);
		albumStat.setStatType(statType);
		albumStat.setStatNum(0);
		albumStatMapper.insert(albumStat);
	}

	@GuiguCache(cacheKey = RedisConstant.ALBUM_STAT_PREFIX+"#{#params[0]}",
				enableLock = true,
				lockName = RedisConstant.ALBUM_STAT_LOCK_PREFIX+"#{#params[0]}"
	)
	@Override
	public AlbumStatVo getAlbumStatVo(Long albumId) {
		return albumStatMapper.getAlbumStatVo(albumId);
	}
}
